package com.fansl.allround.ucenter.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fansl.allround.common.core.bean.SocialInfo;
import com.fansl.allround.common.core.bean.UserInfo;
import com.fansl.allround.common.core.constant.enums.*;
import com.fansl.allround.common.core.exception.AllroundBizException;
import com.fansl.allround.common.core.exception.CheckedException;
import com.fansl.allround.common.core.util.WebUtils;
import com.fansl.allround.open.api.feign.RemoteEmailService;
import com.fansl.allround.open.api.vo.EmailCodeVO;
import com.fansl.allround.ucenter.api.dto.UserRegisterDTO;
import com.fansl.allround.ucenter.api.entity.UcenterUser;
import com.fansl.allround.ucenter.api.entity.UcenterUserOauth;
import com.fansl.allround.ucenter.api.vo.UcenterUserOauthVO;
import com.fansl.allround.ucenter.mapper.UcenterUserMapper;
import com.fansl.allround.ucenter.mapper.UcenterUserOauthMapper;
import com.fansl.allround.ucenter.service.UcenterUserService;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.fansl.allround.common.core.constant.CommonConstants.REGISTER_CODE_EXPIRE_MINUTES;
import static com.fansl.allround.common.core.constant.CommonConstants.REGISTER_CODE_KEY;

/**
 * @author fansl
 * @Description: TODO
 * @date 2019/9/25 17:54
 */
@Service
@AllArgsConstructor
public class UcenterUserServiceImpl extends ServiceImpl<UcenterUserMapper,UcenterUser> implements UcenterUserService {
    private final UcenterUserMapper ucenterUserMapper;
    private final UcenterUserOauthMapper ucenterUserOauthMapper;
    private final RemoteEmailService remoteEmailService;
    private final RedisTemplate redisTemplate;

    /**
     * 获取用户信息
     *
     * @param ucenterUser 用户
     * @return ucenterUserInfo
     */
    @Override
    public UserInfo getUserInfo(UcenterUserOauthVO ucenterUser) {

        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(ucenterUser.getUserId());
        userInfo.setUser(ucenterUser);
        //获取权限信息
        userInfo.setPermissions(ArrayUtil.newArray(String.class,0));
        //获取角色信息
        userInfo.setRoles(ArrayUtil.newArray(Integer.class,0));
        List<UcenterUserOauth> userOauthList = ucenterUserOauthMapper.selectList(Wrappers.<UcenterUserOauth>lambdaQuery()
                .eq(UcenterUserOauth::getUserId,ucenterUser.getUserId()));
        List<SocialInfo> socialInfoList = userOauthList.stream().map(ucenterUserOauth -> {
            SocialInfo socialInfo = new SocialInfo();
            socialInfo.setOauthType(OauthTypeEnum.getByCode(ucenterUserOauth.getOauthId()));
            socialInfo.setUserOauthId(ucenterUserOauth.getUserOauthId());
            socialInfo.setOauthStatus(UserOauthStatusEnum.getByCode(ucenterUserOauth.getStatus()));
            return socialInfo;
        }).collect(Collectors.toList());
        userInfo.setSocialInfoList(socialInfoList);
        return userInfo;
    }

    /**
     * 根据认证类型获取用户信息
     *
     * @param oauthName
     * @param ucenterOauthType
     * @return
     */
    @Override
    public UcenterUserOauthVO getByOauthType(String oauthName, OauthTypeEnum ucenterOauthType) {
        UcenterUserOauthVO ucenterUserOauthVO = new UcenterUserOauthVO();
        switch (ucenterOauthType){
            case PASSWORD:
            case EMAIL:
                UcenterUser ucenterUser = ucenterUserMapper.selectOne(Wrappers.<UcenterUser>lambdaQuery().eq(UcenterUser::getEmail,oauthName));
                ucenterUserOauthVO.setUserId(ucenterUser.getUserId())
                        .setNickname(ucenterUser.getNickname())
                        .setPassword(ucenterUser.getPassword())
                        .setSalt(ucenterUser.getSalt())
                        .setOauthId(ucenterOauthType.getCode())
                        .setOauthValue(ucenterUser.getPassword())
                        .setStatus(UserStatusEnum.NORMAL.getCode())
                        .setOauthStatus(UserOauthStatusEnum.BIND.getCode());
                break;
            case PHONE:
            case WECHAT:
            case QQ:
            case WEIBO:
                ucenterUserOauthVO =
                        ucenterUserMapper.getByOauthType(oauthName,ucenterOauthType.getCode());
                break;
        }

        return ucenterUserOauthVO;
    }

    /**
     * 发送emailCode
     *
     * @param email
     * @return
     */
    @Override
    public boolean sendRegisterCode(String email) {
        EmailCodeVO emailCodeVO =
                remoteEmailService.sendEmailCode(email,EmailMessageTypeEnum.REGISTER);
        if (StrUtil.isBlank(emailCodeVO.getCode())){
            throw new AllroundBizException("服务异常");
        }
        String registerCodeKey = REGISTER_CODE_KEY+email;
        //删除之前的
        redisTemplate.delete(registerCodeKey);
        //插入新增的
        redisTemplate.opsForValue().set(registerCodeKey,emailCodeVO.getCode(),REGISTER_CODE_EXPIRE_MINUTES,TimeUnit.MINUTES);
        return true;
    }

    /**
     * 注册用户
     *
     * @param userRegisterDTO
     * @return
     */
    @Override
    public boolean register(UserRegisterDTO userRegisterDTO) {
        //验证验证码信息
        String registerCodeKey = REGISTER_CODE_KEY+userRegisterDTO.getEmail();
        if(!redisTemplate.hasKey(registerCodeKey)){
           throw new CheckedException("验证码不正确");
        }
        if (!redisTemplate.opsForValue().get(registerCodeKey).equals(userRegisterDTO.getEmailCode())){
            throw new CheckedException("验证码不正确");
        }
        //保存用户信息
        UcenterUser ucenterUser = new UcenterUser();
        ucenterUser.setNickname(userRegisterDTO.getNickname())
                .setSex(SexEnum.UNKNOWN.getType())
                .setPassword(userRegisterDTO.getPassword())
                .setCreateIp(WebUtils.getIP())
                .setSalt(RandomUtil.randomString(6))
                .setStatus(UserStatusEnum.NORMAL.getCode())
                .setEmail(userRegisterDTO.getEmail());
        boolean result = this.save(ucenterUser);
        if(result){
            redisTemplate.delete(registerCodeKey);
        }
        return result;
    }

    /**
     * 注册用户（通过第三方登录的用户）
     *
     * @param ucenterUser
     * @param oauthValue
     * @param oauthType
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean registerUseOauth(UcenterUser ucenterUser,String oauthValue, OauthTypeEnum oauthType) {
        this.save(ucenterUser);
        UcenterUserOauth userOauth = new UcenterUserOauth();
        userOauth.setUserId(ucenterUser.getUserId())
                .setOpenId(oauthValue.getBytes())
                .setOauthId(oauthType.getCode())
                .setStatus(UserOauthStatusEnum.BIND.getCode());
        ucenterUserOauthMapper.insert(userOauth);
        return true;
    }

    /**
     * 创建用户
     *
     * @param ucenterUser
     * @param oauthValue
     * @param ucenterOauthType
     * @return
     */
    @Override
    public UserInfo create(UcenterUser ucenterUser, String oauthValue, OauthTypeEnum ucenterOauthType) {
        this.save(ucenterUser);
        UcenterUserOauth userOauth = new UcenterUserOauth();
        userOauth.setUserId(ucenterUser.getUserId())
                .setOpenId(oauthValue.getBytes())
                .setOauthId(ucenterOauthType.getCode())
                .setStatus(UserOauthStatusEnum.BIND.getCode());
        ucenterUserOauthMapper.insert(userOauth);
        UcenterUserOauthVO ucenterUserOauthVO = new UcenterUserOauthVO();
        ucenterUserOauthVO.setUserId(ucenterUser.getUserId())
                .setNickname(ucenterUser.getNickname())
                .setStatus(ucenterUser.getStatus())
                .setPassword(ucenterUser.getPassword())
                .setSalt(ucenterUser.getSalt())
                .setOauthStatus(userOauth.getStatus())
                .setOauthId(userOauth.getOauthId());
        return getUserInfo(ucenterUserOauthVO);
    }
}
